package com.xuelang.pipeline.app.application.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.xuelang.hiforce.base.tracing.TracingUtils;
import com.xuelang.jadp.client.sys.dto.NgacAssociateDTO;
import com.xuelang.jadp.client.sys.dto.UserInfoDTO;
import com.xuelang.pipeline.app.application.ComponentService;
import com.xuelang.pipeline.app.application.converter.ComponentDTOToComponentConverter;
import com.xuelang.pipeline.app.pipeline.PipelineInstanceService;
import com.xuelang.pipeline.app.pipeline.PipelineService;
import com.xuelang.pipeline.app.resource.request.NgacAssociateXO;
import com.xuelang.pipeline.app.task.TaskInstanceService;
import com.xuelang.pipeline.client.application.dto.ComponentDTO;
import com.xuelang.pipeline.client.application.dto.ComponentQuery;
import com.xuelang.pipeline.client.application.enums.ProgramLanguageEnum;
import com.xuelang.pipeline.client.common.constant.Constant;
import com.xuelang.pipeline.client.common.constant.DictDTO;
import com.xuelang.pipeline.client.common.request.PageParam;
import com.xuelang.pipeline.client.common.result.PageRecord;
import com.xuelang.pipeline.client.common.util.BizAssert;
import com.xuelang.pipeline.client.pipeline.dto.PipelineDTO;
import com.xuelang.pipeline.client.pipeline.dto.PipelineInstanceDTO;
import com.xuelang.pipeline.client.task.enums.TaskInstanceCodeEnum;
import com.xuelang.pipeline.domain.application.Component;
import com.xuelang.pipeline.domain.application.service.ApplicationDomainService;
import com.xuelang.pipeline.domain.application.service.ComponentDomainService;
import com.xuelang.pipeline.domain.application.service.TraitDomainService;
import com.xuelang.sys.app.sys.NgacManagerService;
import com.xuelang.sys.app.sys.UserManagerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 组件服务实现类
 *
 * @author xiwen.zxg
 * @since 2024/5/15
 */
@Slf4j
@Service
public class ComponentServiceImpl implements ComponentService {

    @Autowired
    ComponentDomainService componentDomainService;
    @Autowired
    ApplicationDomainService applicationDomainService;
    @Autowired
    private NgacManagerService ngacManagerService;
    @Autowired
    private UserManagerService userManagerService;
    @Autowired
    private PipelineService pipelineService;
    @Autowired
    TraitDomainService traitDomainService;
    @Autowired
    private PipelineInstanceService pipelineInstanceService;
    @Autowired
    private TaskInstanceService taskInstanceService;

    @Override
    public PageRecord<ComponentDTO> pageList(PageParam<ComponentQuery> dtoPageParam) {
        ComponentQuery condition = dtoPageParam.getCondition();
        condition = condition == null ? new ComponentQuery() : condition;
        PageRecord<Component> pageRecord = componentDomainService.pageList(
                dtoPageParam.getCurrentPage(),
                dtoPageParam.getPageSize(),
                condition);
        return new PageRecord<>(
                pageRecord.getCurrentPage(),
                pageRecord.getPageSize(),
                pageRecord.getTotalCount(),
                pageRecord.getTotalPages(),
                pageRecord.getRecords().stream().map(ComponentDTOToComponentConverter.INSTANCE::componentToComponentDTO).collect(Collectors.toList()));
    }

    @Override
    public List<ComponentDTO> list(ComponentQuery componentQuery) {
        return componentDomainService.list(componentQuery).stream().map(ComponentDTOToComponentConverter.INSTANCE::componentToComponentDTO).collect(Collectors.toList());
    }


    @Override
    public Boolean add(ComponentDTO componentDTO) {
        BizAssert.notNull(componentDTO.getApplicationCode(), "应用编码不能为空");
        BizAssert.notNull(componentDTO.getCode(), "组件编码不能为空");
        BizAssert.notNull(componentDTO.getName(), "组件名称不能为空");
        BizAssert.isTrue(applicationDomainService.existsCode(componentDTO.getApplicationCode()), "应用编码不存在");
        // 校验组件名称不可大于20个字符
        BizAssert.isTrue(componentDTO.getName().length() <= 20, "组件名称需小于20个字符");

        Component component = ComponentDTOToComponentConverter.INSTANCE.componentDTOToComponent(componentDTO);

        Component saveComponent = componentDomainService.save(component);
        boolean saveSuccess = saveComponent != null;
        if (saveSuccess) {
            // 将当前用户设置为管理员
            NgacAssociateDTO ngacAssociate = new NgacAssociateDTO();
            ngacAssociate.setObjectParentId(saveComponent.getApplicationCode());
            // bug: 使用组件编码来关联用户权限
            ngacAssociate.setObjectId(saveComponent.getCode());
            //ngacAssociate.setObjectId(saveComponent.getLabel());
            ngacAssociate.setObjectType(NgacAssociateXO.ObjectTypeEnum.component.name());
            ngacAssociate.setTargetUser(TracingUtils.getUserId());
            ngacAssociate.setUserAttribute(NgacAssociateXO.UserAttribute.builder()
                    .userName(TracingUtils.getUserName())
                    .role(NgacAssociateXO.RoleIdEnum.manager.name())
                    .roleName(NgacAssociateXO.RoleIdEnum.manager.getDescription())
                    .build()
                    .toString());
            ngacManagerService.saveNgacAssociate(ngacAssociate);
        }
        return saveSuccess;
    }

    @Override
    public Boolean update(ComponentDTO componentDTO) {
        BizAssert.notNull(componentDTO.getApplicationCode(), "应用编码不能为空");
        BizAssert.notNull(componentDTO.getCode(), "组件编码不能为空");
        BizAssert.notNull(componentDTO.getLabel(), "组件标签不能为空");
        // 校验组件名称不可大于20个字符
        BizAssert.isTrue(componentDTO.getName().length() <= 20, "组件名称需小于20个字符");
        Component component = ComponentDTOToComponentConverter.INSTANCE.componentDTOToComponent(componentDTO);
        return componentDomainService.update(component);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(String componentLabel) {
        BizAssert.notNull(componentLabel, "组件标签不能为空");
        Component component = componentDomainService.query(componentLabel);
        boolean delete = componentDomainService.delete(componentLabel);
        if (delete) {
            log.info("开始删除组件关联关系");
            // 删除应用权限
            NgacAssociateDTO ngacAssociate = new NgacAssociateDTO();
            ngacAssociate.setObjectId(component.getCode());
            ngacAssociate.setObjectParentId(component.getApplicationCode());
            ngacAssociate.setObjectType(NgacAssociateXO.ObjectTypeEnum.component.name());
            ngacManagerService.removeNgacAssociate(ngacAssociate);
            // 删除组件下资源
            List<PipelineDTO> pipelineDTOList = pipelineService.queryByComponentLabel(componentLabel);
            pipelineDTOList.forEach(p -> pipelineService.delete(p.getCode()));
            // 删除组件管理运维特征
            traitDomainService.deleteByComponentLabel(componentLabel);
        }
        return delete;
    }

    @Override
    public ComponentDTO query(String componentLabel) {
        BizAssert.notNull(componentLabel, "组件标签不能为空");
        Component component = componentDomainService.query(componentLabel);
        ComponentDTO result = ComponentDTOToComponentConverter.INSTANCE.componentToComponentDTO(component);
        if (result != null) {
            String creatorId = result.getCreatorId();
            UserInfoDTO user = userManagerService.getUserById(creatorId);
            if (Objects.nonNull(user)) {
                result.setCreator(user.getRealName());
            } else {
                result.setCreator(Constant.UNKNOWN_USER);
            }
        }
        return result;
    }

    @Override
    public List<DictDTO> queryComponentRepo(String componentLabel) {
        List<DictDTO> dtoList = new ArrayList<>();
        if (StringUtils.isEmpty(componentLabel)) {
            DictDTO dictDTO = new DictDTO();
            //用于处理模板，无结果返回变量值做完选项
            dictDTO.setId("{{componentCodeRepository}}");
            dictDTO.setText("{{componentCodeRepository}}");
            dtoList.add(dictDTO);
            return dtoList;
        }
        Component component = componentDomainService.query(componentLabel);
        DictDTO dictDTO = new DictDTO();
        dictDTO.setId(component.getCodeRepository());
        dictDTO.setText(component.getCodeRepository());
        dtoList.add(dictDTO);
        return dtoList;
    }

    @Override
    public List<DictDTO> queryComponentToken(String componentLabel) {
        List<DictDTO> dtoList = new ArrayList<>();
        if (StringUtils.isEmpty(componentLabel)) {
            DictDTO dictDTO = new DictDTO();
            //用于处理模板，无结果返回变量值做完选项
            dictDTO.setId("{{componentCodeToken}}");
            dictDTO.setText("{{componentCodeToken}}");
            dtoList.add(dictDTO);
            return dtoList;
        }
        Component component = componentDomainService.query(componentLabel);
        DictDTO dictDTO = new DictDTO();
        dictDTO.setId(component.getGitToken());
        dictDTO.setText(component.getGitToken());
        dtoList.add(dictDTO);
        return dtoList;
    }

    @Override
    public ComponentDTO queryById(Long id) {

        Component component =  componentDomainService.queryById(id);
        return ComponentDTOToComponentConverter.INSTANCE.componentToComponentDTO(component);
    }

    @Override
    public List<String> queryComponentImageTagList(Long componentId) {
        List<String> result = Lists.newArrayList();
        Component component = componentDomainService.queryById(componentId);
        List<PipelineInstanceDTO> pipelineInstanceDTOList = pipelineInstanceService.listByComponentLabel(component.getLabel());
        if (CollectionUtils.isEmpty(pipelineInstanceDTOList)) {
            return null;
        }
        pipelineInstanceDTOList.forEach(p -> {
            ProgramLanguageEnum programLanguageEnum = ProgramLanguageEnum.fromValue(component.getProgramLanguage());
            TaskInstanceCodeEnum buildEnum = programLanguageEnum.getImageEnum();
            if (Objects.nonNull(buildEnum)) {
                List<String> outputList = taskInstanceService.queryBuildOutput(p.getInstanceCode(),
                        p.getInstanceCode() + "-" + buildEnum.getValue());
                if(CollectionUtil.isNotEmpty(outputList)) {
                    result.addAll(outputList);
                }
            }
        });

        return result;
    }
}
